package com.jin.webvideo.videoCache.policy;

import com.jin.webvideo.parser.ParseResult;
import com.jin.webvideo.videoCache.policy.condition.*;

import java.util.*;

public class PolicyParser {
    private static final String[] SYMBOLS_ARRAY = {"(", ")", "or", "and", "end"};
    private static Map<String,CacheCondition> map = new HashMap<>();
    /**
     * 缓存条件解析器
     * @param policy
     * @return
     */
    public static CacheCondition parse(String policy){
        if (policy == null){
            policy = "";
        }
        policy = policy.trim();
        if (map.containsKey(policy)){
            return map.get(policy);
        }
        // 如果数据库中的值不断改变map中的值不断增加，没有淘汰策略会造成内存泄漏
        // 测试版本map中仅保存2条数据
        if (map.size() == 2){
            map.clear();
        }
        if (!policy.endsWith("end")){
            policy += " end";
        }
        Queue<String> queue = toQueue(policy);
        queue = infix2Suffix(queue);
        Stack<Condition> numStack = new Stack<>();
        Condition condition = null;
        while (!queue.isEmpty()){
            String temp = queue.poll();
            int priority = priority(temp);
            // 非操作符转化为condition入栈
            if (-1 == priority){
                condition = toCondition(temp);
                numStack.push(condition);
                continue;
            }

            Condition num1 = numStack.pop();
            Condition num2 = numStack.pop();
            if (temp.equalsIgnoreCase("and")){
                condition = new AndCondition<Map<String,String>>(num1, num2);
            }
            else if (temp.equalsIgnoreCase("or")){
                condition = new OrCondition<Map<String,String>>(num1, num2);
            }
            numStack.push(condition);
        }
        if (numStack.empty()){
            numStack.push( (input) -> false);
        }
        CacheCondition cacheCondition = new CacheCondition(numStack.pop());
        map.put(policy, cacheCondition);
        return cacheCondition;
    }

    /**
     * String 转化为相应的StringCondition
     * @param conditionStr
     * @return
     */
    private static Condition toCondition(String conditionStr){
        return new MapCondition(conditionStr);
    }

    /**
     * 将字符串分割成运算符和值
     * @param policy
     * @return
     */
    protected static Queue<String> toQueue(final String policy){
        LinkedList<String> queue = new LinkedList<>();
        String[] parts = policy.split(" ");
        String temp = "";
        for (int i = 0, l = parts.length; i < l; i++){
            String part = parts[i];
            if (-1 == priority(part)){    //非运算符
                temp += part;
                continue;
            }
            // 是运算符
            temp = temp.trim();
            // 操作数非空
            if (!temp.isEmpty()){
                // 操作数入队
                queue.offer(temp);
                temp = "";
            }
            // 操作符入栈
            queue.offer(part);
        }
        // 最后一位是 end
        queue.removeLast();
        return queue;
    }
    protected static int priority(String c){
        for (int i = 0, l = SYMBOLS_ARRAY.length; i < l; i++){
            String symbols = SYMBOLS_ARRAY[i];
            if (symbols.equalsIgnoreCase(c)){
                return i;
            }
        }
        return -1;
    }

    /**
     * 转化为后缀表达式
     * @param queue
     * @return
     */
    protected static Queue<String> infix2Suffix(Queue<String> queue){
        Queue<String> queue2 = new ArrayDeque<>();
        Stack<String> stack = new Stack<>();
        while (!queue.isEmpty()){
            String temp = queue.poll();
            int priority = priority(temp);
            if (-1 == priority){  // 是数字
                queue2.offer(temp);
                continue;
            }
            if (temp.equals("(")){  // (直接入栈
                stack.push(temp);
                continue;
            }
            if (!temp.equals(")")){   //非）
                while (!stack.isEmpty()){
                    if (priority(stack.peek()) < priority){ // 低优先级
                        break;
                    }
                    queue2.offer(stack.pop());
                }
                stack.push(temp);
                continue;
            }
            while (!stack.isEmpty()){   //是）
                String op = stack.pop();
                if (op.equals("(")){   //遇到(
                    break;
                }
                queue2.offer(op);
            }
        }
        while (!stack.isEmpty()){
            String op = stack.pop();
            queue2.offer(op);
        }
        return queue2;
    }
    public static void main(String[] args) {
        PolicyParser parser = new PolicyParser();
        CacheCondition condition = parser.parse("type!=&url==c");
        ParseResult result = new ParseResult("a", "c");
        result.setType("");
        boolean a = condition.compute(result);
        System.out.println(a);
    }
}
